using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using ShadeTree.Binding.Elements;
using ShadeTree.Binding.Validation;
using HorizontalAlignment=System.Windows.HorizontalAlignment;
using TextBox=System.Windows.Controls.TextBox;

namespace ShadeTree.Binding.WPF
{
    public class TextboxElement : BoundScreenElement<TextBox, object>, ITextEditingElement
    {
        private CoerceFunction _coercion;
        private FormatValue _format;

        public TextboxElement(Accessor accessor, TextBox control) : base(accessor, control)
        {
            control.HorizontalAlignment = HorizontalAlignment.Left;

            RegisterLostFocusHandler(()=>editingComplete(null, EventArgs.Empty));
            control.KeyDown += control_KeyDown;

            control.GotKeyboardFocus += control_GotKeyboardFocus;

            if (CoercionUtility.IsNumeric(accessor.PropertyType))
            {
                control.HorizontalAlignment = HorizontalAlignment.Right;
                control.TextAlignment = TextAlignment.Right;
            }

            if (accessor.PropertyType == typeof(string))
            {
                int length = MaximumStringLengthAttribute.GetLength(accessor.InnerProperty);
                control.MaxLength = length;
            }

            _coercion = delegate(Accessor p, string rawValue) { return CoercionUtility.Coerce(p, rawValue); };
            _format = delegate(object o) { return o.ToString(); };
        }

        void control_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            BoundControl.SelectAll();
        }


        public CoerceFunction Coercion
        {
            get { return _coercion; }
            set { _coercion = value; }
        }

        public FormatValue Format
        {
            get { return _format; }
            set { _format = value; }
        }

        protected override bool validatesOnLostFocus()
        {
            return false;
        }

        void control_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                var args = new CancelEventArgs(false);
                fireChanges(args);
            }
        }

        protected void editingComplete(object sender, EventArgs e)
        {
            var ce = new CancelEventArgs(false);
            fireChanges(ce);
            if (!ce.Cancel)
            {
                notify();
            }
        }

        protected void fireChanges(CancelEventArgs e)
        {
            try
            {
                elementValueChanged();
            }
            catch (Exception)
            {
                e.Cancel = true;
                // TODO -- data does not parse
                //SetError(Notification.INVALID_FORMAT);
            }
        }


        protected override object getValueFromControl()
        {
            if (BoundControl.Text == null)
            {
                return null;
            }

            return _coercion(accessor, BoundControl.Text);
        }

        protected override void resetControl(object originalValue)
        {
            if (originalValue == null)
            {
                BoundControl.Text = null;
                return;
            }

            BoundControl.Text = _format(originalValue);
        }

        protected override void tearDown()
        {
            BoundControl.KeyDown -= control_KeyDown;
        }
    }
}